package com.sunwayworld.basemodule.business.folder.service.impl;

import com.sunwayworld.basemodule.basedata.zksample.bean.LimsZkSampleTemplateBean;
import com.sunwayworld.basemodule.basedata.zksample.service.LimsZkSampleTemplateService;
import com.sunwayworld.basemodule.business.batch.bean.LimsBatchBean;
import com.sunwayworld.basemodule.business.batch.bean.LimsBatchSampleBean;
import com.sunwayworld.basemodule.business.batch.bean.LimsBatchSampleProductBean;
import com.sunwayworld.basemodule.business.batch.service.LimsBatchSampleProductService;
import com.sunwayworld.basemodule.business.batch.service.LimsBatchSampleService;
import com.sunwayworld.basemodule.business.batch.service.LimsBatchService;
import com.sunwayworld.basemodule.business.folder.bean.LimsOrderBean;
import com.sunwayworld.basemodule.business.folder.bean.LimsPreOrderTaskBean;
import com.sunwayworld.basemodule.business.folder.service.LimsOrderService;
import com.sunwayworld.basemodule.business.folder.service.LimsPreOrderTaskService;
import com.sunwayworld.basemodule.business.ordertask.bean.LimsOrderTaskBean;
import com.sunwayworld.basemodule.business.ordertask.bean.LimsRunBoardHoleBean;
import com.sunwayworld.basemodule.business.ordertask.service.LimsOrderTaskService;
import com.sunwayworld.basemodule.business.ordertask.service.LimsRunBoardHoleService;
import com.sunwayworld.basemodule.business.prefolder.bean.LimsPreFolderBean;
import com.sunwayworld.basemodule.business.prefolder.service.LimsPreFolderService;
import com.sunwayworld.basemodule.business.result.bean.LimsRunBean;
import com.sunwayworld.basemodule.business.result.service.LimsRunService;
import com.sunwayworld.basemodule.coredata.experimentaltemplate.bean.LimsExperimentalTemplateTestBean;
import com.sunwayworld.basemodule.coredata.experimentaltemplate.service.LimsExperimentalTemplateTestService;
import com.sunwayworld.basemodule.samplemanage.sample.bean.LimsSampleBean;
import com.sunwayworld.basemodule.samplemanage.sample.service.LimsSampleService;
import com.sunwayworld.framework.exception.InvalidDataException;
import com.sunwayworld.framework.i18n.I18nHelper;
import com.sunwayworld.framework.mybatis.mapper.MapperParameter;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.support.PersistableHelper;
import com.sunwayworld.framework.utils.CollectionUtils;
import com.sunwayworld.framework.utils.NumberUtils;
import com.sunwayworld.framework.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.sunwayworld.framework.at.annotation.AuditTrailType;
import com.sunwayworld.framework.at.annotation.AuditTrailEntry;
import com.sunwayworld.framework.spring.annotation.GikamBean;

import com.sunwayworld.basemodule.business.folder.dao.LimsFolderDao;
import com.sunwayworld.basemodule.business.folder.bean.LimsFolderBean;
import com.sunwayworld.basemodule.business.folder.service.LimsFolderService;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;

import java.util.*;
import java.util.stream.Collectors;

@Repository
@GikamBean
public class LimsFolderServiceImpl implements LimsFolderService {

    @Autowired
    private LimsFolderDao limsFolderDao;

    @Lazy
    @Autowired
    private LimsBatchService batchService;

    @Lazy
    @Autowired
    private LimsRunBoardHoleService runBoardHoleService;

    @Lazy
    @Autowired
    private LimsRunService runService;

    @Lazy
    @Autowired
    private LimsBatchSampleService batchSampleService;

    @Lazy
    @Autowired
    private LimsBatchSampleProductService batchSampleProductService;

    @Lazy
    @Autowired
    private LimsOrderService orderService;

    @Lazy
    @Autowired
    private LimsOrderTaskService orderTaskService;

    @Lazy
    @Autowired
    private LimsPreOrderTaskService preOrderTaskService;

    @Lazy
    @Autowired
    private LimsSampleService sampleService;

    @Lazy
    @Autowired
    private LimsExperimentalTemplateTestService etTestService;

    @Lazy
    @Autowired
    private LimsPreFolderService limsPreFolderService;


    @Override
    @SuppressWarnings("unchecked")
    public LimsFolderDao getDao() {
        return limsFolderDao;
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public Long insert(RestJsonWrapperBean jsonWrapper) {
        LimsFolderBean limsFolder = jsonWrapper.parseUnique(LimsFolderBean.class);
        limsFolder.setId(ApplicationContextHelper.getNextIdentity());
        getDao().insert(limsFolder);
        return limsFolder.getId();
    }

    @Transactional
    @Override
    public void addQcSample(RestJsonWrapperBean wrapper) {
        Long firstTestId = NumberUtils.parseLong(wrapper.getParamValue("firstTestId"));
        Long runId = NumberUtils.parseLong(wrapper.getParamValue("runId"));
        String runCode = wrapper.getParamValue("runCode");
        LimsRunBean runBean = runService.selectById(runId);
        List<LimsZkSampleTemplateBean> zkSampleTemplateBeans = wrapper.parse(LimsZkSampleTemplateBean.class);
        LimsBatchBean qcBatch = getQCBatch();
        List<Long> spIds = zkSampleTemplateBeans.stream().map(LimsZkSampleTemplateBean::getSpId).distinct().collect(Collectors.toList());
        List<LimsExperimentalTemplateTestBean> spTestBeans = etTestService.selectListByFilter(SearchFilter.instance()
                .match("etId", spIds).filter(MatchPattern.OR));
        if (spTestBeans.isEmpty()) return;
        Optional<LimsExperimentalTemplateTestBean> any = spTestBeans.stream().filter(s -> s.getOrderNo() == 1 && !firstTestId.equals(s.getTestId())).findAny();
        if (any.isPresent()) {
            List<LimsExperimentalTemplateTestBean> testBeans = spTestBeans.stream().filter(s -> s.getOrderNo() == 1 && !firstTestId.equals(s.getTestId())).collect(Collectors.toList());
            List<Long> testEtIds = testBeans.stream().map(LimsExperimentalTemplateTestBean::getEtId).distinct().collect(Collectors.toList());
            List<LimsZkSampleTemplateBean> teckLineBeans = zkSampleTemplateBeans.stream().filter(f -> testEtIds.contains(f.getSpId())).collect(Collectors.toList());
            List<String> sampleType = teckLineBeans.stream().map(t -> t.getExt$Item("sampleType")).distinct().collect(Collectors.toList());
            throw new InvalidDataException(I18nHelper.getMessage("FOLLEWING.SAMPLE") + "<br/>" + StringUtils.join(sampleType, "<br/>") + "<br/>" + I18nHelper.getMessage("FIRSTTEST.AND.CURRENT.TEST.DIFFERENT"));
        }
        List<LimsBatchSampleBean> insertBatchSampleList = new ArrayList<>();
        List<LimsSampleBean> insertSampleList = new ArrayList<>();
        List<LimsBatchSampleProductBean> insertBatchSampleProjectList = new ArrayList<>();
        List<LimsFolderBean> insertFolderList = new ArrayList<>();
        List<LimsOrderBean> insertOrderList = new ArrayList<>();
        List<LimsPreOrderTaskBean> insertPreOrderTaskList = new ArrayList<>();
        List<LimsOrderTaskBean> insertOrderTaskList = new ArrayList<>();
        List<LimsPreFolderBean> preFolderBeans = new ArrayList<>();
        for (LimsZkSampleTemplateBean sampleTecklineBean : zkSampleTemplateBeans) {
            LimsSampleBean sampleBean = new LimsSampleBean();
            String sampleCode = ApplicationContextHelper.getNextSequence("T_LIMS_SAMPLE", "Q");
            sampleBean.setId(ApplicationContextHelper.getNextIdentity());
            sampleBean.setQcSampleFlg("1");
            sampleBean.setOriNo(sampleCode);
            sampleBean.setSampleCode(sampleCode);
            sampleBean.setSampleType(sampleTecklineBean.getExt$Item("sampleType"));
            sampleBean.setSampleTypeCode(sampleTecklineBean.getExt$Item("sampleTypeCode"));
            sampleBean.setStatus("inExperiment");
            sampleBean.setHandleType("wait");
            insertSampleList.add(sampleBean);// 样本
            LimsBatchSampleBean batchSampleBean = new LimsBatchSampleBean();
            batchSampleBean.setId(ApplicationContextHelper.getNextIdentity());
            batchSampleBean.setBatchId(qcBatch.getId());
            batchSampleBean.setBatchCode(qcBatch.getBatchCode());
            batchSampleBean.setSampleId(sampleBean.getId());
            batchSampleBean.setSampleCode(sampleCode);
            insertBatchSampleList.add(batchSampleBean);// 样例
            LimsBatchSampleProductBean sampleProductBean = new LimsBatchSampleProductBean();
            sampleProductBean.setId(ApplicationContextHelper.getNextIdentity());
            sampleProductBean.setBatchId(qcBatch.getId());
            sampleProductBean.setBatchCode(qcBatch.getBatchCode());
            sampleProductBean.setBatchSampleId(batchSampleBean.getId());
            sampleProductBean.setSampleId(sampleBean.getId());
            sampleProductBean.setSampleCode(sampleCode);
            sampleProductBean.setProductCode("QC01");
            sampleProductBean.setProductName("QC01");
            sampleProductBean.setStatus("inExperiment");
            insertBatchSampleProjectList.add(sampleProductBean);// 检测项目
            List<LimsExperimentalTemplateTestBean> spTestBeanList = spTestBeans.stream().filter(f -> f.getEtId().equals(sampleTecklineBean.getSpId())).collect(Collectors.toList());
            if (spTestBeanList.isEmpty()) {
                return;
            }

            // 质控样添加prefolder表记录
            LimsPreFolderBean preFolderBean = new LimsPreFolderBean();
            preFolderBean.setId(ApplicationContextHelper.getNextIdentity());
            preFolderBean.setBatchId(sampleProductBean.getBatchId());
            preFolderBean.setBatchCode(sampleProductBean.getBatchCode());
            preFolderBean.setBatchSampleId(sampleProductBean.getBatchSampleId());
            preFolderBean.setSampleId(sampleProductBean.getSampleId());
            preFolderBean.setSampleCode(sampleProductBean.getSampleCode());
            preFolderBean.setSampleTypeCode(sampleBean.getSampleTypeCode());
            preFolderBean.setSampleTypeName(sampleBean.getSampleType());
            preFolderBean.setProductId(sampleProductBean.getProductId());
            preFolderBean.setProductCode(sampleProductBean.getProductCode());
            preFolderBean.setProductName(sampleProductBean.getProductName());
            preFolderBean.setEtId(sampleTecklineBean.getSpId());
            preFolderBean.setEtCode(sampleTecklineBean.getExt$Item("etCode"));
            preFolderBean.setEtName(sampleTecklineBean.getExt$Item("etName"));
            preFolderBean.setJudgId(sampleTecklineBean.getSpecId());
            preFolderBean.setJudgCode(sampleTecklineBean.getExt$Item("judgCode"));
            preFolderBean.setStatus("done");
            preFolderBeans.add(preFolderBean);

            LimsFolderBean folderBean = new LimsFolderBean();
            folderBean.setPreFolderId(preFolderBean.getId());
            folderBean.setId(ApplicationContextHelper.getNextIdentity());
            folderBean.setBatchId(qcBatch.getId());
            folderBean.setBatchCode(qcBatch.getBatchCode());
//            folderBean.setFolderCode(ApplicationContextHelper.getNextSequence(getDao().getTable(), "F"));
            folderBean.setProductId(sampleProductBean.getId()); // 质检 虚拟数据
            folderBean.setProductCode(sampleProductBean.getProductCode());
            folderBean.setProductName(sampleProductBean.getProductName());
            folderBean.setBatchSampleId(batchSampleBean.getId());
            folderBean.setOriNo(sampleCode);
            folderBean.setEtId(sampleTecklineBean.getSpId());
            folderBean.setEtCode(sampleTecklineBean.getExt$Item("etCode"));
            folderBean.setEtName(sampleTecklineBean.getExt$Item("etName"));
            folderBean.setJudgId(sampleTecklineBean.getSpecId());
            folderBean.setJudgCode(sampleTecklineBean.getExt$Item("judgCode"));
            insertFolderList.add(folderBean);
            LimsOrderBean orderBean = new LimsOrderBean();
            orderBean.setId(ApplicationContextHelper.getNextIdentity());
            orderBean.setFolderId(folderBean.getId());
            orderBean.setSampleId(sampleBean.getId());
            orderBean.setSampleCode(sampleBean.getSampleCode());
            orderBean.setSampleTypeName(sampleTecklineBean.getExt$Item("sampleType"));
            orderBean.setSampleTypeCode(sampleTecklineBean.getExt$Item("sampleTypeCode"));
            insertOrderList.add(orderBean);
            spTestBeanList.sort(Comparator.comparingLong(LimsExperimentalTemplateTestBean::getOrderNo));
            for (int i = 0; i < spTestBeanList.size(); i++) {
                LimsExperimentalTemplateTestBean spTest = spTestBeanList.get(i);


                LimsPreOrderTaskBean preOrderTaskBean = new LimsPreOrderTaskBean();

                preOrderTaskBean.setId(ApplicationContextHelper.getNextIdentity());
                preOrderTaskBean.setFolderId(folderBean.getId());
                preOrderTaskBean.setTestId(spTest.getTestId());
                preOrderTaskBean.setTestCode(spTest.getTestCode());
                preOrderTaskBean.setTestName(spTest.getTestName());
                preOrderTaskBean.setSort(spTest.getOrderNo());
                preOrderTaskBean.setEtTestId(spTest.getId());
                preOrderTaskBean.setLastEtTestIds(spTest.getLastTestIds());
                preOrderTaskBean.setStatus("draft");
                if (i == 0) {
                    LimsOrderTaskBean orderTaskBean = new LimsOrderTaskBean();
                    orderTaskBean.setId(ApplicationContextHelper.getNextIdentity());
                    orderTaskBean.setBatchId(folderBean.getBatchId());
                    orderTaskBean.setBatchCode(folderBean.getBatchCode());
                    orderTaskBean.setFolderId(folderBean.getId());
                    orderTaskBean.setOrderId(orderBean.getId());
                    orderTaskBean.setSampleId(orderBean.getSampleId());
                    orderTaskBean.setSampleCode(orderBean.getSampleCode());
                    orderTaskBean.setPreOrderTaskId(preOrderTaskBean.getId());
                    orderTaskBean.setTestId(spTest.getTestId());
                    orderTaskBean.setTestCode(spTest.getTestCode());
                    orderTaskBean.setTestName(spTest.getTestName());
                    orderTaskBean.setEtTestId(spTest.getId());
                    orderTaskBean.setSort(spTest.getOrderNo());
                    orderTaskBean.setParallelId(ApplicationContextHelper.getNextIdentity());
                    orderTaskBean.setRunId(runId);
                    orderTaskBean.setRunCode(runCode);
                    orderTaskBean.setAddInRun("1");
                    orderTaskBean.setMethodCode(runBean.getMethodCode());
                    orderTaskBean.setMethodDesc(runBean.getMethodDesc());
                    orderTaskBean.setTesterId(runBean.getAnalystId());
                    orderTaskBean.setTester(runBean.getAnalystName());
                    orderTaskBean.setReviewer(runBean.getReviewer());
                    orderTaskBean.setReviewerId(runBean.getReviewerId());
                    orderTaskBean.setTestMethodId(runBean.getTestMethodId());
                    insertOrderTaskList.add(orderTaskBean);

                    preOrderTaskBean.setOrderTaskId(orderTaskBean.getId());
                    preOrderTaskBean.setStatus("logged");
                }
                insertPreOrderTaskList.add(preOrderTaskBean);
            }
        }
        batchSampleService.getDao().fastInsert(insertBatchSampleList);
        batchSampleProductService.getDao().fastInsert(insertBatchSampleProjectList);
        sampleService.getDao().fastInsert(insertSampleList);

        getDao().fastInsert(insertFolderList);
        preOrderTaskService.getDao().fastInsert(insertPreOrderTaskList);
        orderTaskService.getDao().fastInsert(insertOrderTaskList);
        orderService.getDao().fastInsert(insertOrderList);
        limsPreFolderService.getDao().fastInsert(preFolderBeans);
    }

    @Transactional
    @Override
    public void deleteQcSample(RestJsonWrapperBean jsonWrapperBean) {
        List<LimsOrderTaskBean> taskBeans = jsonWrapperBean.parse(LimsOrderTaskBean.class);
        if (taskBeans == null) return;
        List<Long> orderIds = taskBeans.stream().map(LimsOrderTaskBean::getOrderId).distinct().collect(Collectors.toList());
        List<Long> folderIds = taskBeans.stream().map(LimsOrderTaskBean::getFolderId).distinct().collect(Collectors.toList());
        List<Long> sampleIds = taskBeans.stream().map(LimsOrderTaskBean::getSampleId).distinct().collect(Collectors.toList());
        List<Long> holeIds = taskBeans.stream().map(LimsOrderTaskBean::getBoardHoleId).filter(Objects::nonNull).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(holeIds)) {
            LimsRunBoardHoleBean runBoardHoleBean = new LimsRunBoardHoleBean();
            runBoardHoleBean.setOrderTaskId(null);
            runBoardHoleBean.setSampleFlag(null);
            runBoardHoleBean.setStockType("free");
            runBoardHoleService.getDao().updateByIds(runBoardHoleBean, holeIds, "orderTaskId", "sampleFlag", "stockType");
        }
        if (sampleIds.isEmpty()) return;
        List<LimsSampleBean> limsSampleBeans = sampleService.selectListByIds(sampleIds);
        List<LimsFolderBean> folderBeans = selectListByIds(folderIds);
        List<Long> batchSampleIds = folderBeans.stream().map(LimsFolderBean::getBatchSampleId).collect(Collectors.toList());
        List<Long> preFolderIds = folderBeans.stream().map(LimsFolderBean::getPreFolderId).filter(Objects::nonNull).collect(Collectors.toList());
        batchSampleService.getDao().deleteByIdList(batchSampleIds); // 删订单样例
        List<LimsBatchSampleProductBean> sampleProjectBeans = new ArrayList<>();
        batchSampleIds.forEach(id -> {
            LimsBatchSampleProductBean sampleProjectBean = new LimsBatchSampleProductBean();
            sampleProjectBean.setBatchSampleId(id);
            sampleProjectBeans.add(sampleProjectBean);
        });
        batchSampleProductService.getDao().deleteBy(sampleProjectBeans, "batchSampleId"); // 通过订单样例ID删 项目
        sampleService.getDao().deleteBy(limsSampleBeans); // 删样本

        getDao().deleteByIdList(folderIds);  // 删folder
        orderService.getDao().deleteByIdList(orderIds);  //删order

        List<LimsPreOrderTaskBean> preOrderTaskBeans = new ArrayList<>();
        folderIds.forEach(id -> {
            LimsPreOrderTaskBean preOrderTaskBean = new LimsPreOrderTaskBean();
            preOrderTaskBean.setFolderId(id);
            preOrderTaskBeans.add(preOrderTaskBean);
        });
        preOrderTaskService.getDao().deleteBy(preOrderTaskBeans, "folderId"); // 通过folderId 删 preOrderTask
        orderTaskService.getDao().deleteBy(taskBeans);// 删orderTask
        if (!preFolderIds.isEmpty()) {
            limsPreFolderService.getDao().deleteByIdList(preFolderIds);
        }
    }

    // 所有质控样 都属于该订单下
    private LimsBatchBean getQCBatch() {
        String batchCode = "QC001";
        LimsBatchBean batchBean = batchService.selectFirstByFilter(SearchFilter.instance().match("batchCode", batchCode).filter(MatchPattern.EQ));
        if (batchBean == null) {
            batchBean = new LimsBatchBean();
            batchBean.setBatchCode(batchCode);
            batchBean.setId(ApplicationContextHelper.getNextIdentity());
            batchBean.setStatus("done");
            batchBean.setBatchType("QC");
            batchService.getDao().insert(batchBean);
        }
        return batchBean;
    }

    @Override
    public List<LimsFolderBean> selectForReport(MapperParameter mapperParameter) {
        return getDao().selectForReport(mapperParameter).parallelStream().map(e ->
                PersistableHelper.mapToPersistable(e, LimsFolderBean.class)).collect(Collectors.toList());
    }
}
